import {Editor, Element, Frame, NodeData, Nodes, NodeTree, SerializedNode, useEditor} from '@craftjs/core';
import {Button, message, Modal, Tour} from 'antd';
import {createElement, useEffect, useRef, useState} from "react";
import * as BaseComponents from './BaseComponents';
import {Chat, TChatCallbackData} from "./components/Chat";
import {Container} from './components/Container';
import {SettingPanel} from './settingPanel';
import {ToolBox} from './toolBox';
import {Tools} from './tools';
import {RexProConfigProvider} from "@jeoshi-design/rex-design.other.core";
import {request, useModel, useRequest} from "@umijs/max";
import {LeftOutlined, RightOutlined} from '@ant-design/icons';

import styles from './styles.less';

type StageProps = {
  initData?: string;
  appendContent?: TChatCallbackData | null;
};

type TemplateProps = {
  initData?: string;
  preview?: boolean;
};

const Stage: React.FC<StageProps> = ({initData, appendContent}) => {
  const {preview, actions, query} = useEditor((state) => ({preview: !state.options.enabled, }));
  const [leftCollapsed, setLeftCollapsed] = useState(false);
  const [rightCollapsed, setRightCollapsed] = useState(false);
  const {current: componentIdCache} = useRef<Record<string, string>>({});
  const {run: getDetailApi} = useRequest(
    (id: number, type: 'Template' | 'Kit') => {
      if (type === 'Kit') {
        return request(`/api/kits/${id}`, {method: 'get', });
      }
      return request(`/api/template/${id}`, {method: 'get', });
    },
    {manual: true, },
  );

  const parseNodeTree = (source: Nodes, rootKeys: string[]) => {
    const parseNode = (nodeTree: NodeTree, item: NodeData, parent: string) => {
      const node = query.parseSerializedNode({...item, nodes: [], linkedNodes: {}, parent} as SerializedNode).toNode();
      nodeTree.nodes[node.id] = node;
      if (Array.isArray(item.nodes) && item.nodes.length) {
        item.nodes.forEach((subKey) => {
          const subNode = parseNode(nodeTree, source[subKey] as unknown as NodeData, node.id);
          node.data.nodes.push(subNode.id);
          nodeTree.nodes[subNode.id] = subNode;
        })
      }
      if (Object.keys(item.linkedNodes).length) {
        Object.keys(item.linkedNodes).forEach((componentId) => {
          const subKey = item.linkedNodes[componentId];
          const subNode = parseNode(nodeTree, source[subKey] as unknown as NodeData, node.id);
          node.data.linkedNodes[componentId] = subNode.id;
          nodeTree.nodes[subNode.id] = subNode;
        })
      }
      if (parent === 'ROOT') {
        nodeTree.rootNodeId = node.id;
      }
      return node;
    };
    rootKeys.forEach((key) => {
      const item = source[key] as unknown as NodeData;
      const data: NodeTree = {rootNodeId: '', nodes: {}, };
      parseNode(data, item, 'ROOT');
      actions.addNodeTree(data, 'ROOT');
    });
  };

  const confirm = (data: TChatCallbackData) => {
    if ('id' in data) {
      const modalData = Modal.confirm({
        title: '检测到新内容',
        content: `检测到${data.type === 'Kit' ? '套件' : '模板'}「${data.name}」，请选择操作方式：`,
        footer (originNode, extra) {
          return (
            <div className={styles.footerDiv}>
              <extra.CancelBtn />
              <Button onClick={async () => {
                try {
                  const res = await getDetailApi(data.id, data.type);
                  const jsonData = JSON.parse(res.content);
                  actions.deserialize(jsonData)
                  modalData.destroy();
                } catch (error) {
                  message.error('解析失败或请求失败2');
                }
              }}>覆盖当前内容</Button>
              <extra.OkBtn />
            </div>
          )
        },
        okText: '追加到当前内容',
        onOk: async () => {
          try {
            const res = await getDetailApi(data.id, data.type);
            const jsonData = JSON.parse(res.content);
            parseNodeTree(jsonData, (jsonData.ROOT as unknown as NodeData).nodes);
          } catch (error) {
            console.error(error);
            message.error('解析失败或请求失败1');
          }
        }
      });
    }
    else if ('templateType' in data) {
      const isRender = componentIdCache[data.componentId] && !!query.node(componentIdCache[data.componentId])?.toSerializedNode();
      Modal.confirm({
        title: '检测到新内容',
        content: `检测到组件「${data.templateType}」，请选择操作方式：`,
        okText: isRender ? '替换' : '追加到当前内容',
        onOk: async () => {
          try {
            const options = query.getOptions();
            const node = query.parseReactElement(createElement(options.resolver[data.templateType], data.params)).toNodeTree();
            if (isRender) {
              actions.setProp(componentIdCache[data.componentId], (props) => {
                Object.keys(data.params).forEach(key => {
                  props[key] = (data.params as any)[key];
                })
              });
            }
            else {
              componentIdCache[data.componentId] = node.rootNodeId;
              actions.addNodeTree(node, 'ROOT');
            }
          } catch (error) {
            console.error(error);
            message.error('解析失败3');
          }
        }
      });
    }
  };

  useEffect(() => {
    if (appendContent && ('id' in appendContent || 'templateType' in appendContent)) {
      confirm(appendContent);
    }
  }, [appendContent]);

  useEffect(() => {
    const fn = (e: CustomEvent<TChatCallbackData>) => {
      const data = e.detail;
      if (!data) return;
      confirm(data);
    };
    document.addEventListener('SHARE_TEMPLATE_MESSAGE', fn as any);
    return () => {
      document.removeEventListener('SHARE_TEMPLATE_MESSAGE', fn as any);
    }
  }, [])

  return (
    <div className={styles.mainDiv}>
      <div className={styles.headerDiv}>IAS Editor <Tools /></div>

      <div className={styles.contentDiv}>
        {!preview && (
          <div id='component-panel' className={leftCollapsed ? styles.leftPanelCollapsed : styles.leftPanel}>
            {!leftCollapsed && (<div className={styles.toolBoxDiv}><ToolBox /></div>)}
            <div className={styles.leftCollapseBtn} onClick={() => setLeftCollapsed(!leftCollapsed)}>
              {leftCollapsed ? <RightOutlined style={{fontSize: '12px'}} /> : <LeftOutlined style={{fontSize: '12px'}} />
              }
            </div>
          </div>
        )}
        <div id='design-canvas' className={styles.canvasDiv}>
          <Frame data={initData}>
            <Element canvas is="div"/>
          </Frame>
        </div>
        {!preview && (
          <div id='property-panel' className={rightCollapsed ? styles.rightPanelCollapsed : styles.rightPanel}>
            {!rightCollapsed && (<div className={styles.settingPanelDiv}><SettingPanel /></div>)}
            <div className={styles.rightCollapseBtn} onClick={() => setRightCollapsed(!rightCollapsed)}>
              {rightCollapsed ? <LeftOutlined style={{fontSize: '12px'}} /> : <RightOutlined style={{fontSize: '12px'}} />
              }
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

const TemplateTour = () => {
  const [currentStep, setCurrentStep] = useState(0);
  const {isTour, setIsTour} = useModel('global');


  return (
    <Tour
      open={isTour}
      onClose={() => {
        // localStorage.setItem('tourShown', 'true');
        setIsTour(false);
      }}
      steps={[
        {
          title: '组件库',
          description: '左侧是组件库，您可以拖拽各种组件到画布上进行页面设计',
          target: () => document.getElementById('component-panel') as HTMLElement,
          placement: 'right'
        },
        {
          title: '设计画布',
          description: '中间是设计区域，您可以在这里自由布局和调整页面元素',
          target: () => document.getElementById('design-canvas') as HTMLElement,
          placement: 'top',
          // autoAdjustOverflow: false,
        },
        {
          title: '属性设置',
          description: '右侧是属性面板，您可以在这里调整选中组件的各种属性',
          target: () => document.getElementById('property-panel') as HTMLElement,
          placement: 'left'
        },
        {
          title: '智能助手',
          description: '通过右下角的智能助手，您可以用自然语言快速生成页面',
          target: () => document.getElementById('tourChat') as HTMLElement,
          placement: 'left'
        }
      ]}
      current={currentStep}
      onChange={setCurrentStep}
    />
  )
}

const Template: React.FC<TemplateProps> = ({initData, preview}) => {
  const enabled = preview === undefined ? true : Boolean(Number(preview));
  const [appendContent, setAppendContent] = useState<TChatCallbackData>();

  useEffect(() => {}, [])

  return (
    <RexProConfigProvider value={{
      apiClient: async (path, params) => {
        const res = await request('/api/mock' + path, {data: params, method: 'post'});
        return res.data;
      }
    }}>
      <TemplateTour />
      <div>
        <Editor resolver={{Container, ...BaseComponents}} enabled={enabled}>
          <Stage initData={initData} appendContent={appendContent} />
        </Editor>
        <Chat callback={(data) => {setAppendContent(data)}} />
      </div>
    </RexProConfigProvider>
  );
};

export default Template;
